import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import axios from 'axios';
import axiosRetry from 'axios-retry';

import { store } from '@/store';

import { securityRenewal } from '@/services/base/denglumokuaidenglujiekou';

import { HttpCodeMessage, ServerError } from './config';
import { hideLoading, replaceMultiText, showFail, showLoading, showSuccess } from './util';

export const request = axios.create();

axiosRetry(request, {
  retries: 1,
  retryCondition: async (err) => {
    if (
      err.config &&
      err.config.url &&
      err.config.headers.token &&
      err.response?.status === ServerError.unlogin
    ) {
      if (
        ['/security/logout', '/security/renewal'].some((url) =>
          url.endsWith(err.config!.url as string)
        )
      ) {
        return false;
      }

      const [, token] = await securityRenewal({
        tupleResponse: true,
        skipErrorHandler: true,
        headers: {
          token: err.config.headers.token
        }
      });

      if (token?.data) {
        localStorage.setItem('token', token.data);
        request.defaults.headers.token = token.data;
        // 修改token
        err.config.headers.token = token.data;

        if (!err.config.url?.endsWith('/security/self')) {
          await store.getUserInfoByToken(token.data);
        }

        return true;
      }

      void store.logout();

      return false;
    }

    return false;
  }
});

request.defaults.baseURL = import.meta.env.VITE_PROXY_KEY;
request.defaults.headers.post['Content-Type'] = 'application/json';

/** 请求参数配置 */
type Option<D = any> = AxiosRequestConfig<D> & {
  /** 请求类型 */
  requestType?: 'form';
  /** 是否过滤业务逻辑请求判断 */
  skipErrorHandler?: boolean;
  /** 是否显示加载中 */
  loading?: boolean | string;
  /** 是否显示错误提示 */
  fail?: boolean | string;
  /** 是否显示成功提示 */
  success?: boolean | string;
};

type OptionWithTupleResponse<D = any> = Option<D> & {
  /** 是否元祖返回, 默认为true */
  tupleResponse: true;
};

type OptionWithoutTupleResponse<D = any> = Option<D> & {
  /** 是否元祖返回 */
  tupleResponse: false;
};

interface API {
  <T = any, R = AxiosResponse<T>, D = any>(
    url: string,
    config: OptionWithTupleResponse<D>
  ): Promise<TupleResponse<T>>;
  <T = any, R = AxiosResponse<T>, D = any>(
    url: string,
    config: OptionWithoutTupleResponse<D>
  ): Promise<T>;
  <T = any, R = AxiosResponse<T>, D = any>(url: string, config?: Option<D>): Promise<T>;
}

const api: API = async <T = any, R = AxiosResponse<T>, D = any>(
  url: string,
  opt: Option<D> & {
    tupleResponse?: boolean;
  } = {}
) => {
  const { requestType, skipErrorHandler, loading, fail, success, tupleResponse, ...config } = opt;

  // 请求接口地址
  const resolveUrl = replaceMultiText(url, '/');

  if (loading) {
    showLoading(loading);
  }

  if (requestType) {
    if (!config.headers) {
      config.headers = {};
    }

    if (requestType === 'form') {
      config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
    }
  }

  const res = await new Promise<TupleResponse<T>>((resolve) => {
    request<T>({
      url: resolveUrl,
      ...config,
      skipErrorHandler
    } as Option<D>)
      .then(async (data) => {
        if (config.responseType === 'blob') {
          return resolve([undefined, data as T, data]);
        }

        const resData = data.data as unknown as ServerResponse<T>;

        // 跳过错误处理
        if (skipErrorHandler) {
          return resolve([undefined, resData as T, data]);
        }
        // end 跳过错误处理

        // http状态码错误处理
        if (resData.status !== 200) {
          return resolve([
            resData.message ||
              HttpCodeMessage[resData.status as keyof typeof HttpCodeMessage] ||
              '请求失败',
            resData.data,
            data
          ]);
        }

        // end http状态码错误处理

        // 业务错误处理
        if (!resData.success) {
          return resolve([resData.message || '请求失败', resData as T, data]);
        }
        // end 业务错误处理

        return resolve([undefined, resData as T, data]);
      })
      .catch((e) => {
        // 是否取消
        if (axios.isCancel(e)) {
          return resolve([]);
        }

        const msg = e?.response?.data?.message ?? (e as Error)?.message ?? '请求失败';
        // 其他错误处理
        resolve([msg]);
        // end 其他错误处理
      });
  });

  hideLoading();

  // 错误提醒
  if (res[0]) {
    if (!skipErrorHandler && fail !== false) {
      setTimeout(() => {
        showFail(typeof fail === 'string' ? fail : res[0]);
      }, 100);
    }
  } else if (success) {
    setTimeout(() => {
      showSuccess(
        typeof success === 'string'
          ? success
          : (res[1] as unknown as ServerResponse<T>)?.message || '请求成功'
      );
    }, 100);
  }

  // 元祖返回
  if (tupleResponse === true) {
    return res;
  }

  // 非元祖返回, 错误处理
  if (res[0]) {
    return Promise.reject(res[0]);
  }

  return res[1];
};

export { api };
